package top.superflow.flow.inner

import org.springframework.beans.BeansException
import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.context.ApplicationContext
import top.superflow.exception.RequestUnsupportedException
import top.superflow.flow.common.OriginalProcessProxyMethodTools
import top.superflow.flow.runtime.inf.IOSchema
import top.superflow.flow.runtime.io.DefaultIOSchema
import top.superflow.flow.runtime.processprovider.OriginalProcessProxy
import top.superflow.lang.CollectionUtils

class InnerSpringOriginalProcessProxy(applicationContext: ApplicationContext) extends OriginalProcessProxy with OriginalProcessProxyMethodTools{

  final val  EXPECTED_BEAN_KEY = "bean"

  override def execute(params: Map[String,Any]): Any = {
    val bean = getObject
    val method = getMethod
    validateParameters(method, params)
    method.invoke(bean, mapToObjectArray(method, params):_*)
  }

  protected def getObject : Any = {
    val beanName = getBeanName
    try {
      applicationContext.getBean(beanName)
    } catch {
      case nbe:NoSuchBeanDefinitionException => throw new RequestUnsupportedException("There is no bean named as [" + beanName + "] in the application context, there are only [" + applicationContext.getBeanDefinitionNames + "]" , nbe)
      case e : BeansException => throw new RequestUnsupportedException("Could not obtain the bean [" + beanName + "]", e )
    }
  }


  private def getBeanName : String = {
    val metadata = getMetadata

    if(metadata.contains(EXPECTED_BEAN_KEY)){
      return metadata.get(EXPECTED_BEAN_KEY).get.toString
    }

    throw new RequestUnsupportedException("There is no bean name configured in the meta data of the process configuration!")

  }

  override def getMetadata : Map[String, Any] = {
    val metadata = super.getMetadata

    if(metadata == null || CollectionUtils.isEmpty(metadata)){
      throw new RequestUnsupportedException("The entry key should not be null and the meta data in the identity should not empty!")
    }

    metadata
  }

  override def getInputSchema: IOSchema = {
    val inputSchema = DefaultIOSchema.getInputSchema

    val method = getMethod

    val parameters = method.getParameters

    if(CollectionUtils.isEmpty(parameters)){
      return inputSchema
    }

    val typeSchemas = getTypeSchema(method)

    inputSchema.setSchema(typeSchemas)

    inputSchema.setCount(parameters.size)

    inputSchema
  }

  protected def getProcessClass: Class[_] = {
    val bean = getObject
    bean.getClass
  }
}
